Skip to content

feat(canvas/terminal): "Not available" banner for runtimes without a TTY - #2830

Merged
HongmingWang-Rabbit merged 1 commit into
stagingfrom
ux/terminal-tab-external-not-available
May 5, 2026
Merged

HongmingWang-Rabbit merged 1 commit into
stagingfrom
ux/terminal-tab-external-not-available

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

External-runtime workspaces don't have a shell endpoint, so opening the Terminal tab produced a spurious "Connection failed" with a Reconnect button. Now: render a clean "Terminal not available" banner with a big terminal-off icon, runtime name, and a pointer to the Chat tab.

Behavior

  • `data.runtime === "external"` (or any future entry in `RUNTIMES_WITHOUT_TERMINAL`) → early-return the banner; xterm + WebSocket are not initialised at all.
  • `claude-code` and every other runtime → unchanged.
  • `data` prop omitted → falls through to normal mount (back-compat).

Test plan

  • 4 new vitest cases in `TerminalTab.notAvailable.test.tsx`:
    • external renders banner with runtime name
    • external does NOT open a WebSocket (load-bearing — we want zero spurious 404s on the workspace-server)
    • claude-code mounts normally (regression cover)
    • data omitted falls through
  • Build + full vitest pass: 1258 tests / 89 files.
  • Browser verify: select an external workspace → click Terminal tab → see the banner with the slashed-terminal icon and "This workspace runs the external runtime, which doesn't expose a shell".

🤖 Generated with Claude Code

Pre-fix TerminalTab tried to open /ws/terminal/<id> for every workspace
including external ones (which have no shell endpoint on the
workspace-server). The server returned 404, status flipped to "error",
the user saw "Connection failed" with a Reconnect button — reading as
a bug when really the runtime intentionally has no TTY.

Now: when data.runtime is in RUNTIMES_WITHOUT_TERMINAL (currently just
"external"), TerminalTab renders a NotAvailablePanel with a big
terminal-off icon and a one-line explanation including the runtime
name. The xterm + WebSocket dance is skipped entirely — no spurious
404s, no scary error UI, no Reconnect that can't help.

The runtime is determined from the data prop now threaded by
SidePanel.tsx (existing pattern for ChatTab/ConfigTab/etc).

Tests: 4 new in TerminalTab.notAvailable.test.tsx pin: external
renders banner with runtime name, external doesn't open WS, claude-
code mounts normally (regression cover for the early-return scope),
data omitted falls through (back-compat).

Build clean. 1258 tests pass.
@HongmingWang-Rabbit
HongmingWang-Rabbit added this pull request to the merge queue May 5, 2026
Merged via the queue into staging with commit ca6e7c3 May 5, 2026
21 of 22 checks passed
@HongmingWang-Rabbit
HongmingWang-Rabbit deleted the ux/terminal-tab-external-not-available branch May 5, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant